<template>
    <div>
        <el-input v-model="searchWords" style="width: 240px;cursor: pointer;" placeholder="点击打开搜索框" @click="openDialog" :prefix-icon="Search" readonly />
        <el-dialog v-model="dialogVisible" :title="dialogTitle" width="640" :close-on-click-modal="false">
            <RepeatList :template="templateObj" :min="1" :max="handledColumns.length || 1"
                add-text="新增条件" del-text="删除条件" @change="onRepeatListChange" ref="repeatListRef" >
                <template #item="{ item }">
                    <div class="item-box">
                        <el-select
                            v-model="item.prop"
                            placeholder="选择字段"
                            class="label-wrapper"
                            filterable
                            @change="onColumnChange(item)"
                        >
                            <el-option
                                v-for="column in handledColumns"
                                :key="column.prop"
                                :label="column.label"
                                :value="column.prop"
                            />
                        </el-select>

                        <div class="value-wrapper">
                            <el-input
                                v-if="ColumnTypeMap[item.prop] === SearchTypeEnum.text"
                                v-model="item.value"
                                :placeholder="getPlaceholder(item)"
                                clearable
                            />
                            <el-select
                                v-else-if="isSelectType(item.prop)"
                                v-model="item.value"
                                :multiple="getColumn(item.prop)?.mutiple"
                                :collapse-tags="!!getColumn(item.prop)?.mutiple"
                                :placeholder="getPlaceholder(item)"
                                clearable
                                filterable
                                style="width: 100%;"
                            >
                                <el-option
                                    v-for="option in getOptions(item.prop)"
                                    :key="option.value"
                                    :label="option.label"
                                    :value="option.value"
                                />
                            </el-select>
                            <el-date-picker
                                v-else-if="isDatePickerType(item.prop)"
                                v-model="item.value"
                                :type="getDatePickerType(item.prop)"
                                :value-format="getDateValueFormat(item.prop)"
                                :format="getDateDisplayFormat(item.prop)"
                                :placeholder="getPlaceholder(item)"
                                :range-separator="getRangeSeparator(item.prop)"
                                :start-placeholder="getRangePlaceholder(item.prop)?.[0]"
                                :end-placeholder="getRangePlaceholder(item.prop)?.[1]"
                                clearable
                                style="width: 100%;"
                            />
                            <el-time-picker
                                v-else-if="ColumnTypeMap[item.prop] === SearchTypeEnum.time"
                                v-model="item.value"
                                :is-range="isTimeRange(item.prop)"
                                :format="getTimeDisplayFormat(item.prop)"
                                :value-format="getTimeValueFormat(item.prop)"
                                :placeholder="getPlaceholder(item)"
                                :range-separator="getRangeSeparator(item.prop)"
                                :start-placeholder="getRangePlaceholder(item.prop)?.[0]"
                                :end-placeholder="getRangePlaceholder(item.prop)?.[1]"
                                clearable
                                style="width: 100%;"
                            />
                        </div>
                    </div>
                </template>
            </RepeatList>
            <template #footer>
                <div class="dialog-footer">
                    <el-button @click="cancelDialog">关闭</el-button>
                    <el-button @click="resetDialog">重置</el-button>
                    <el-button type="primary" @click="confirmDialog">确认</el-button>
                </div>
            </template>
        </el-dialog>
    </div>
</template>

<script lang="ts" setup>
// 搜索组件：组内且的关系，组外或的关系(暂时只写组内)
// 搜索类型： 字符串、枚举（多选或单选）、字典（多选或单选）、时间、日期、日期范围
import RepeatList from './repeatList.vue';
import { computed, reactive, ref, watch } from 'vue';
import { SearchTypeEnum, type ColumnOption, type ColumnType, type SearchType } from './search';
import { Search, } from '@element-plus/icons-vue'

type NormalizedColumnOption = {
    label: string;
    value: string | number | boolean;
};

type ResolvedColumn = Omit<ColumnType, 'options'> & { options: NormalizedColumnOption[] };


const props = defineProps<{
    columns?: ColumnType[];
    title?: string;
}>();

const emit = defineEmits<{
    (e: 'confirm', payload: { list: SearchCondition[]; resultText: string; resultObject: Record<string, unknown> }): void;
    (e: 'reset'): void;
    (e: 'cancel'): void;
}>();

type SearchCondition = {
    uid?: string;
    prop: string;
    value: unknown;
    type?: SearchType;
    mutiple?: boolean;
};

const dialogTitle = computed(() => props.title || '搜索条件');

/**
 * 构建一列的默认配置，补齐缺省字段。
 */
const getDefaultColumn = (): ColumnType => ({
    label: '',
    prop: '',
    value: '',
    type: SearchTypeEnum.text,
    mutiple: false,
    options: [],
});

/**
 * 将 columns 中允许的多种 option 形式统一为 { label, value }。
 */
const normalizeOption = (option: ColumnOption) => {
    if (typeof option === 'object' && option !== null && 'label' in option && 'value' in option) {
        return {
            label: String(option.label),
            value: option.value as string | number | boolean,
        };
    }
    return {
        label: String(option),
        value: option as string | number | boolean,
    };
};

/**
 * 根据字段类型推导默认的初始值结构。
 */
const getInitialValue = (column?: ColumnType) => {
    if (!column) return '';
    if (column.value !== undefined && column.value !== null) {
        if (Array.isArray(column.value)) {
            return [...column.value];
        }
        return column.value;
    }
    const columnType = (column.type || SearchTypeEnum.text) as SearchType;
    if (columnType === SearchTypeEnum.enum || columnType === SearchTypeEnum.dict) {
        return column.mutiple ? [] : '';
    }
    if (columnType === SearchTypeEnum.daterange) {
        return ['', ''];
    }
    if (columnType === SearchTypeEnum.date) {
        if (column.dateType?.includes('range')) {
            return ['', ''];
        }
        return '';
    }
    if (columnType === SearchTypeEnum.time) {
        if (column.dateType === 'timerange' || column.mutiple) {
            return ['', ''];
        }
        return '';
    }
    return '';
};

/**
 * 合并默认配置与外部传入的 columns，得到最终使用的列集合。
 */
const handledColumns = computed<ResolvedColumn[]>(() => {
    const sourceColumns = props.columns && props.columns.length ? props.columns : [];
    return sourceColumns.map((item) => {
        const merged: ColumnType = {
            ...getDefaultColumn(),
            ...item,
        };
        return {
            ...merged,
            value: getInitialValue(merged),
            options: (merged.options || []).map(normalizeOption),
        } as ResolvedColumn;
    });
});

/**
 * 以 prop 为 key 做映射，便于按字段名查询配置。
 */
const columnMap = computed<Record<string, ResolvedColumn>>(() =>
    handledColumns.value.reduce((acc, column) => {
        if (column.prop) {
            acc[column.prop] = column;
        }
        return acc;
    }, {} as Record<string, ResolvedColumn>),
);

/**
 * 缓存每个字段对应的类型，模板中根据类型决定控件。
 */
const ColumnTypeMap = computed<Record<string, SearchType>>(() =>
    handledColumns.value.reduce((obj, item) => {
        if (item.prop) {
            obj[item.prop] = (item.type as SearchType) || SearchTypeEnum.text;
        }
        return obj;
    }, {} as Record<string, SearchType>),
);

const templateObj = reactive<SearchCondition>({
    prop: '',
    value: '',
    type: SearchTypeEnum.text,
    mutiple: false,
});

const searchWords = ref<string>('');
const dialogVisible = ref<boolean>(false);
const repeatListRef = ref<InstanceType<typeof RepeatList>>();
const repeatListValue = ref<SearchCondition[]>([]);

/**
 * 打开搜索条件弹窗。
 */
const openDialog = () => {
    dialogVisible.value = true;
};

/**
 * 格式化搜索条件列表，生成展示文本与对象结果。
 */
const finalizeResults = (list: SearchCondition[]) => {
    const filteredList = list.filter((item) => item.prop);
    const resultText = filteredList
        .map((item) => {
            const column = columnMap.value[item.prop];
            const displayValue = formatValue(item.value, column);
            return `${column?.label || item.prop}=${displayValue}`;
        })
        .join('; ');
    const resultObject = filteredList.reduce<Record<string, unknown>>((obj, item) => {
        obj[item.prop] = item.value;
        return obj;
    }, {});
    searchWords.value = resultText;
    return { filteredList, resultText, resultObject };
};

/**
 * 将结果回传给父组件，内部复用 finalizeResults。
 */
const handleResult = () => {
    const list = repeatListRef.value?.getDataList() as SearchCondition[] | undefined;
    console.log(list);
    const { filteredList, resultText, resultObject } = finalizeResults(list || []);
    emit('confirm', {
        list: filteredList,
        resultText,
        resultObject,
    });
};

/**
 * 关闭弹窗但不提交结果。
 */
const cancelDialog = () => {
    dialogVisible.value = false;
    emit('cancel');
};

/**
 * 清空条件并通知父组件做重置处理。
 */
const resetDialog = () => {
    repeatListValue.value = [];
    repeatListRef.value?.reset();
    searchWords.value = '';
    emit('reset');
};

/**
 * 提交结果并关闭弹窗。
 */
const confirmDialog = () => {
    handleResult();
    dialogVisible.value = false;
};

/**
 * RepeatList 内部触发 change 时，同步最新数据。
 */
const onRepeatListChange = (list: SearchCondition[]) => {
    repeatListValue.value = list;
};

/**
 * 更换字段时重置类型、多选状态以及初始值。
 */
const onColumnChange = (item: SearchCondition) => {
    const column = getColumn(item.prop);
    if (!column) {
        item.value = '';
        item.type = SearchTypeEnum.text;
        item.mutiple = false;
        return;
    }
    item.type = column.type || SearchTypeEnum.text;
    item.mutiple = !!column.mutiple;
    item.value = getInitialValue(column);
};

const getColumn = (prop: string) => columnMap.value[prop];

/**
 * 判断当前字段是否需要使用下拉选择器。
 */
const isSelectType = (prop: string) => {
    const type = ColumnTypeMap.value[prop];
    return type === SearchTypeEnum.enum || type === SearchTypeEnum.dict;
};

/**
 * 判断当前字段是否需要日期选择器。
 */
const isDatePickerType = (prop: string) => {
    const type = ColumnTypeMap.value[prop];
    return type === SearchTypeEnum.date || type === SearchTypeEnum.daterange;
};

/**
 * 获取字段配置中的枚举/字典选项。
 */
const getOptions = (prop: string) => {
    const column = getColumn(prop);
    return column?.options || [];
};

/**
 * 推导日期控件的 type（date、daterange、datetimerange 等）。
 */
const getDatePickerType = (prop: string) => {
    const column = getColumn(prop);
    const baseType = ColumnTypeMap.value[prop];
    if (column?.dateType) return column.dateType;
    if (baseType === SearchTypeEnum.daterange) return 'daterange';
    if (baseType === SearchTypeEnum.date) return 'date';
    return 'date';
};

/**
 * 日期展示格式（format），默认按类型推导。
 */
const getDateDisplayFormat = (prop: string) => {
    const column = getColumn(prop);
    if (column?.format) return column.format;
    const pickerType = getDatePickerType(prop);
    if (pickerType.includes('time')) {
        return 'YYYY-MM-DD HH:mm:ss';
    }
    if (pickerType.includes('month')) {
        return 'YYYY-MM';
    }
    return 'YYYY-MM-DD';
};

/**
 * 日期值格式（valueFormat），用于提交给后端。
 */
const getDateValueFormat = (prop: string) => {
    const column = getColumn(prop);
    if (column?.valueFormat) return column.valueFormat;
    const pickerType = getDatePickerType(prop);
    if (pickerType.includes('time')) {
        return 'YYYY-MM-DD HH:mm:ss';
    }
    if (pickerType.includes('month')) {
        return 'YYYY-MM';
    }
    return 'YYYY-MM-DD';
};

/**
 * 判断时间字段是否为时间范围选择。
 */
const isTimeRange = (prop: string) => {
    const column = getColumn(prop);
    return column?.dateType === 'timerange' || !!column?.mutiple;
};

/**
 * 时间选择器展示格式。
 */
const getTimeDisplayFormat = (prop: string) => {
    const column = getColumn(prop);
    if (column?.format) return column.format;
    return 'HH:mm:ss';
};

/**
 * 时间值格式，默认返回 HH:mm:ss。
 */
const getTimeValueFormat = (prop: string) => {
    const column = getColumn(prop);
    if (column?.valueFormat) return column.valueFormat;
    return 'HH:mm:ss';
};

/**
 * 获取时间/日期范围的分隔符。
 */
const getRangeSeparator = (prop: string) => {
    const column = getColumn(prop);
    return column?.rangeSeparator || '至';
};

/**
 * 范围选择时的开始/结束占位符。
 */
const getRangePlaceholder = (prop: string) => {
    const column = getColumn(prop);
    return column?.placeholders;
};

/**
 * 根据字段类型生成输入控件的 placeholder。
 */
const getPlaceholder = (item: SearchCondition) => {
    const column = getColumn(item.prop);
    if (!column) return '请选择字段后输入';
    if (column.placeholders && column.placeholders.length === 1 && !isSelectType(item.prop)) {
        return column.placeholders[0];
    }
    const type = ColumnTypeMap.value[item.prop];
    switch (type) {
        case SearchTypeEnum.text:
            return '请输入搜索值';
        case SearchTypeEnum.enum:
        case SearchTypeEnum.dict:
            return '请选择搜索值';
        case SearchTypeEnum.date:
        case SearchTypeEnum.daterange:
            return '请选择日期';
        case SearchTypeEnum.time:
            return '请选择时间';
        default:
            return '请输入搜索值';
    }
};

/**
 * 统一处理结果的展示文本，枚举类会映射为标签。
 */
const formatValue = (value: unknown, column?: ResolvedColumn) => {
    if (value === null || value === undefined || value === '') {
        return '';
    }
    if (Array.isArray(value)) {
        if (column && isSelectType(column.prop) && column.options) {
            const normalized = column.options.map(normalizeOption);
            return value
                .map((item) => {
                    const match = normalized.find((option) => option.value === item);
                    return match ? match.label : String(item);
                })
                .filter((item) => item !== '')
                .join(',');
        }
        return value.filter((item) => item !== '' && item !== undefined && item !== null).join(',');
    }
    if (column && isSelectType(column.prop) && column.options) {
        const normalized = column.options.map(normalizeOption);
        const match = normalized.find((option) => option.value === value);
        if (match) {
            return match.label;
        }
    }
    return String(value);
};

watch(
    () => handledColumns.value,
    () => {
        repeatListValue.value = repeatListRef.value?.getDataList() || [];
    },
    { deep: true },
);
</script>

<style lang="scss" scoped>
.item-box {
    display: flex;
    align-items: center;
    column-gap: 20px;
    flex: 1;

    .label-wrapper {
        flex: 2;
    }

    .value-wrapper {
        flex: 3;
    }
}

.dialog-footer {
    padding-top: 15px;
    display: flex;
    justify-content: flex-end;
    border-top: 1px solid #e5e5e5;
}
</style>